﻿using HarmonyLib;
using MarriageFertility.Extensions;
using MarriageFertility.Helpers;
using MarriageFertility.Texts;
using TaleWorlds.CampaignSystem;
using TaleWorlds.CampaignSystem.Conversation;
using TaleWorlds.CampaignSystem.Conversation.Tags;
using TaleWorlds.CampaignSystem.Extensions;
using TaleWorlds.Localization;
using System.Collections.Generic;

namespace MarriageFertility.Patches
{
    [HarmonyPatch(typeof(ConversationHelper))]
    internal sealed class ConversationHelperPatches
    {
        private static List<string> _relationList;

        [HarmonyPatch("GetHeroRelationToHeroTextShort")]
        private static bool Prefix(ref string __result, Hero queriedHero, Hero baseHero, bool uppercaseFirst)
        {
            _relationList = new List<string>();
            TextObject relationText = GetHeroRelationToHeroTextShort(queriedHero, baseHero);

            if (relationText.Length > 0)
            {
                relationText.SetCharacterProperties("NPC", queriedHero.CharacterObject);
                string result = relationText.ToString();

                // Adjust case if necessary
                if (!string.IsNullOrEmpty(result))
                {
                    char[] charArray = result.ToCharArray();
                    result = uppercaseFirst ? char.ToUpper(charArray[0]) + result.Substring(1) : char.ToLower(charArray[0]) + result.Substring(1);
                }

                __result = result;
                return false; // Skip original method
            }

            // Fallback to generic relative text
            TextObject fallbackText = RelationText.RelativeOfPlayerText;
            fallbackText.SetCharacterProperties("NPC", queriedHero.CharacterObject);
            __result = fallbackText.ToString();
            return false;
        }

        private static TextObject GetHeroRelationToHeroTextShort(Hero queriedHero, Hero baseHero)
        {
            // Initialize empty text
            TextObject relationText = RelationText.EmptyText;

            // Self-check
            if (baseHero == queriedHero)
            {
                if (queriedHero == Hero.MainHero)
                    return RelationText.YouText;
                if (queriedHero.IsPlayerCompanion)
                    return RelationText.CompanionText;
                if (queriedHero.IsWanderer && !queriedHero.IsPlayerCompanion)
                    return RelationText.WandererText;
                if (queriedHero.IsNotable)
                    return RelationText.NotableText;
                if (queriedHero.IsRuralNotable)
                    return RelationText.RuralNotableText;
                return RelationText.HeroText;
            }
            
            if (RelationHelper.IsHusband(baseHero, queriedHero))
                return RelationText.HusbandText;
            if (RelationHelper.IsWife(baseHero, queriedHero))
                return RelationText.WifeText;
            if (RelationHelper.IsExHusband(baseHero, queriedHero))
                return RelationText.ExHusbandText;
            if (RelationHelper.IsExWife(baseHero, queriedHero))
                return RelationText.ExWifeText;
            if (baseHero.IsSexFriend(queriedHero))
                return RelationText.SexFriendText;
            
            if (RelationHelper.IsHusbandFather(baseHero, queriedHero))
                return RelationText.HusbandFatherText;
            if (RelationHelper.IsHusbandMother(baseHero, queriedHero))
                return RelationText.HusbandMotherText;
            if (RelationHelper.IsWifeFather(baseHero, queriedHero))
                return RelationText.WifeFatherText;
            if (RelationHelper.IsWifeMother(baseHero, queriedHero))
                return RelationText.WifeMotherText;
            
            if (baseHero.Father == queriedHero)
                return RelationText.FatherText;
            if (baseHero.Mother == queriedHero)
                return RelationText.MotherText;
            
            foreach (Hero sibling in baseHero.Siblings)
            {
                if (sibling == queriedHero)
                {
                    if (baseHero.Age < queriedHero.Age)
                        return queriedHero.IsFemale ? RelationText.ElderSisterText : RelationText.ElderBrotherText;
                    return queriedHero.IsFemale ? RelationText.YoungerSisterText : RelationText.YoungerBrotherText;
                }
                else if (sibling.Spouse == queriedHero)
                {
                    if (sibling.IsFemale)
                        return sibling.Age < baseHero.Age ? RelationText.ElderSisterHusbandText : RelationText.YoungerSisterHusbandText;
                    return sibling.Age < baseHero.Age ? RelationText.ElderBrotherWifeText : RelationText.YoungerBrotherWifeText;
                }
                else if (CheckNieceNephew(sibling, queriedHero))
                {
                    return queriedHero.IsFemale ? RelationText.NieceText : RelationText.NephewText;
                }
            }
            
            foreach (Hero child in baseHero.Children)
            {
                if (child == queriedHero)
                    return queriedHero.IsFemale ? RelationText.DaughterText : RelationText.SonText;
                if (child.Spouse == queriedHero)
                    return queriedHero.IsFemale ? RelationText.DaughterInLawText : RelationText.SonInLawText;
                if (CheckGrandchildren(child, queriedHero))
                    return queriedHero.IsFemale ? RelationText.GranddaughterText : RelationText.GrandsonText;
            }
            
            if (CheckGrandparent(baseHero.Father, queriedHero))
                return RelationText.PaternalGrandfatherText;
            if (CheckGrandparent(baseHero.Mother, queriedHero))
                return RelationText.MaternalGrandfatherText;
            if (CheckGrandparent(baseHero.Father?.Spouse, queriedHero))
                return RelationText.PaternalGrandmotherText;
            if (CheckGrandparent(baseHero.Mother?.Spouse, queriedHero))
                return RelationText.MaternalGrandmotherText;
            
            if (CheckPaternalAuntUncle(baseHero, queriedHero, out TextObject auntUncleText))
                return auntUncleText;
            if (CheckMaternalAuntUncle(baseHero, queriedHero))
                return queriedHero.IsFemale ? RelationText.MaternalAuntText : RelationText.MaternalUncleText;
            
            if (CheckCousin(baseHero, queriedHero, out TextObject cousinText))
                return cousinText;

            return relationText;
        }

        private static bool CheckNieceNephew(Hero sibling, Hero queriedHero, int order = 0)
        {
            foreach (Hero child in sibling.Children)
            {
                if (child == queriedHero)
                    return order == 0; 
                if (child.Spouse == queriedHero)
                    return order == 0; 
                if (CheckNieceNephew(child, queriedHero, order + 1))
                    return true;
            }
            return false;
        }

        private static bool CheckGrandchildren(Hero child, Hero queriedHero, int order = 1)
        {
            foreach (Hero grandChild in child.Children)
            {
                if (grandChild == queriedHero)
                    return order == 1; 
                if (grandChild.Spouse == queriedHero)
                    return order == 1; 
                if (CheckGrandchildren(grandChild, queriedHero, order + 1))
                    return true; 
            }
            return false;
        }

        private static bool CheckGrandparent(Hero parent, Hero queriedHero, int order = 1)
        {
            if (parent == null)
                return false;
            if (parent == queriedHero)
                return order == 1;
            return CheckGrandparent(parent.Father, queriedHero, order + 1) || CheckGrandparent(parent.Mother, queriedHero, order + 1);
        }

        private static bool CheckPaternalAuntUncle(Hero baseHero, Hero queriedHero, out TextObject auntUncleText)
        {
            auntUncleText = RelationText.EmptyText;

            if (baseHero.Father != null)
            {
                foreach (Hero sibling in baseHero.Father.Siblings)
                {
                    if (sibling == queriedHero || sibling.Spouse == queriedHero)
                    {
                        if (sibling.IsFemale)
                            auntUncleText = RelationText.PaternalAuntText;
                        else
                            auntUncleText = sibling.Age > baseHero.Father.Age ? RelationText.PaternalElderUncleText : RelationText.PaternalYoungerUncleText;
                        return true;
                    }
                }
            }
            return false;
        }

        private static bool CheckMaternalAuntUncle(Hero baseHero, Hero queriedHero)
        {
            if (baseHero.Mother != null)
            {
                foreach (Hero sibling in baseHero.Mother.Siblings)
                {
                    if (sibling == queriedHero)
                        return true;
                    if (sibling.Spouse == queriedHero)
                        return true;
                }
            }
            return false;
        }

        private static bool CheckCousin(Hero baseHero, Hero queriedHero, out TextObject cousinText)
        {
            cousinText = RelationText.EmptyText;

            if (baseHero.Father != null)
            {
                foreach (Hero sibling in baseHero.Father.Siblings)
                {
                    foreach (Hero cousin in sibling.Children)
                    {
                        if (cousin == queriedHero || cousin.Spouse == queriedHero)
                        {
                            if (cousin.IsFemale)
                                cousinText = cousin.Age < baseHero.Age ? RelationText.ElderFemaleCousinText : RelationText.YoungerFemaleCousinText;
                            else
                                cousinText = cousin.Age < baseHero.Age ? RelationText.ElderMaleCousinText : RelationText.YoungerMaleCousinText;
                            return true;
                        }
                        if (CheckCousin(cousin, queriedHero, out cousinText))
                            return true;
                    }
                }
            }
            if (baseHero.Mother != null)
            {
                foreach (Hero sibling in baseHero.Mother.Siblings)
                {
                    foreach (Hero cousin in sibling.Children)
                    {
                        if (cousin == queriedHero || cousin.Spouse == queriedHero)
                        {
                            if (cousin.IsFemale)
                                cousinText = cousin.Age < baseHero.Age ? RelationText.ElderFemaleCousinText : RelationText.YoungerFemaleCousinText;
                            else
                                cousinText = cousin.Age < baseHero.Age ? RelationText.ElderMaleCousinText : RelationText.YoungerMaleCousinText;
                            return true;
                        }
                        if (CheckCousin(cousin, queriedHero, out cousinText))
                            return true;
                    }
                }
            }
            return false;
        }
    }

    [HarmonyPatch(typeof(PlayerIsSpouseTag), "IsApplicableTo")]
    internal sealed class PlayerIsSpouseTagPatch
    {
        private static void Postfix(ref bool __result, CharacterObject character)
        {
            if (__result) return;
            __result = character.IsHero && Hero.MainHero.ExSpouses.Contains(character.HeroObject);
        }
    }
}